```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>数据结构可视化指南</title>
    <link href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
    <link href="https://cdn.staticfile.org/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js"></script>
    <style>
        body {
            font-family: 'Noto Sans SC', Tahoma, Arial, Roboto, "Droid Sans", "Helvetica Neue", "Droid Sans Fallback", "Heiti SC", "Hiragino Sans GB", Simsun, sans-serif;
            background-color: #f8fafc;
            color: #1e293b;
            line-height: 1.6;
        }
        .hero {
            background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%);
            color: white;
        }
        .card {
            transition: all 0.3s ease;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        }
        .card:hover {
            transform: translateY(-5px);
            box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1);
        }
        .highlight {
            position: relative;
            padding-left: 1.5rem;
        }
        .highlight:before {
            content: "";
            position: absolute;
            left: 0;
            top: 0;
            height: 100%;
            width: 4px;
            background: linear-gradient(to bottom, #4f46e5, #7c3aed);
            border-radius: 2px;
        }
        .data-structure-img {
            border-radius: 8px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
            transition: transform 0.3s ease;
        }
        .data-structure-img:hover {
            transform: scale(1.02);
        }
        .code-block {
            background-color: #1e293b;
            color: #f8fafc;
            border-radius: 6px;
            overflow-x: auto;
        }
        .comparison-table {
            border-collapse: separate;
            border-spacing: 0;
            overflow: hidden;
            border-radius: 8px;
        }
        .comparison-table th, .comparison-table td {
            padding: 12px 16px;
            text-align: left;
        }
        .comparison-table thead th {
            background-color: #4f46e5;
            color: white;
        }
        .comparison-table tbody tr:nth-child(odd) {
            background-color: #f1f5f9;
        }
        .comparison-table tbody tr:nth-child(even) {
            background-color: #e2e8f0;
        }
    </style>
</head>
<body class="antialiased">
    <!-- Hero Section -->
    <div class="hero py-20 px-6 md:px-12 lg:px-24">
        <div class="max-w-4xl mx-auto text-center">
            <h1 class="text-4xl md:text-5xl lg:text-6xl font-bold mb-6 font-serif">数据结构可视化指南</h1>
            <p class="text-xl md:text-2xl opacity-90 mb-8">探索数据结构的核心概念、优缺点及应用场景</p>
            <div class="flex justify-center space-x-4">
                <span class="px-4 py-2 bg-white bg-opacity-20 rounded-full text-sm font-medium">高效存储</span>
                <span class="px-4 py-2 bg-white bg-opacity-20 rounded-full text-sm font-medium">快速检索</span>
                <span class="px-4 py-2 bg-white bg-opacity-20 rounded-full text-sm font-medium">算法优化</span>
            </div>
        </div>
    </div>

    <!-- Main Content -->
    <div class="max-w-6xl mx-auto px-6 py-12">
        <!-- Array Section -->
        <section class="mb-16">
            <div class="flex items-center mb-6">
                <div class="bg-indigo-100 w-10 h-10 rounded-full flex items-center justify-center mr-4">
                    <i class="fas fa-layer-group text-indigo-600"></i>
                </div>
                <h2 class="text-3xl font-bold font-serif">数组特点</h2>
            </div>
            
            <div class="grid md:grid-cols-2 gap-8">
                <div class="highlight p-6 bg-white rounded-xl">
                    <p class="mb-4">存储区间是连续，且占用内存严重，空间复杂也很大。</p>
                    
                    <h3 class="text-xl font-semibold mb-3 text-indigo-600">优点</h3>
                    <ul class="space-y-2 mb-6">
                        <li class="flex items-start">
                            <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
                            <span>随机读取效率很高，原因数组是连续（随机访问性强，查找速度快）</span>
                        </li>
                    </ul>
                    
                    <h3 class="text-xl font-semibold mb-3 text-rose-600">缺点</h3>
                    <ul class="space-y-2">
                        <li class="flex items-start">
                            <i class="fas fa-times-circle text-rose-500 mt-1 mr-2"></i>
                            <span>插入和删除数据效率低，因插入数据，这个位置后面的数据在内存中要往后移的，且大小固定不易动态扩展</span>
                        </li>
                    </ul>
                </div>
                
                <div>
                    <img src="https://cdn.nlark.com/yuque/0/2021/png/21449790/1630845979929-fbf0e42e-3571-4692-99e7-02eb41fa42b1.png" alt="数组结构图" class="w-full h-auto data-structure-img">
                </div>
            </div>
        </section>

        <!-- Linked List Section -->
        <section class="mb-16">
            <div class="flex items-center mb-6">
                <div class="bg-blue-100 w-10 h-10 rounded-full flex items-center justify-center mr-4">
                    <i class="fas fa-link text-blue-600"></i>
                </div>
                <h2 class="text-3xl font-bold font-serif">链表特点</h2>
            </div>
            
            <div class="grid md:grid-cols-2 gap-8">
                <div class="highlight p-6 bg-white rounded-xl">
                    <p class="mb-4">区间离散，占用内存宽松，空间复杂度小。</p>
                    
                    <h3 class="text-xl font-semibold mb-3 text-blue-600">优点</h3>
                    <ul class="space-y-2 mb-6">
                        <li class="flex items-start">
                            <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
                            <span>删除速度快，内存利用率高，没有大小固定，扩展灵活</span>
                        </li>
                    </ul>
                    
                    <h3 class="text-xl font-semibold mb-3 text-rose-600">缺点</h3>
                    <ul class="space-y-2">
                        <li class="flex items-start">
                            <i class="fas fa-times-circle text-rose-500 mt-1 mr-2"></i>
                            <span>不能随机查找，每次都是从第一个开始遍历（查询效率低）</span>
                        </li>
                    </ul>
                </div>
                
                <div class="space-y-4">
                    <img src="https://cdn.nlark.com/yuque/0/2021/png/21449790/1630845995324-42e12b7c-6e0f-49cd-9d86-a823ee3e4bc6.png" alt="链表结构图" class="w-full h-auto data-structure-img">
                    <img src="https://cdn.nlark.com/yuque/0/2021/png/21449790/1630846000455-e2c3f212-42ea-4c5a-b294-f45f61ea047e.png" alt="链表示意图" class="w-full h-auto data-structure-img">
                </div>
            </div>
        </section>

        <!-- Hash Section -->
        <section class="mb-16">
            <div class="flex items-center mb-6">
                <div class="bg-purple-100 w-10 h-10 rounded-full flex items-center justify-center mr-4">
                    <i class="fas fa-hashtag text-purple-600"></i>
                </div>
                <h2 class="text-3xl font-bold font-serif">Hash结构</h2>
            </div>
            
            <div class="grid md:grid-cols-2 gap-8 mb-8">
                <div class="highlight p-6 bg-white rounded-xl">
                    <p class="mb-4">散列表（Hash table，也叫哈希表），是根据<strong>关键码值(Key value)</strong>而直接进行访问的数据结构。也就是说，它通过把关键码值<strong>映射到</strong>表中一个位置来访问记录，以加快查找的速度。这个映射函数叫做<strong>散列函数</strong>，存放记录的数组叫做<strong>散列表</strong>。</p>
                    
                    <p class="mb-4">最典型的的例子就是字典，大家估计小学的时候也用过不少新华字典吧，如果我想要获取"按"字详细信息，我肯定会去根据拼音an去查找 拼音索引，我们首先去查an在字典的位置，查了一下得到"安"，结果如下。这过程就是键码映射，在公式里面，就是通过key去查找f(key)。其中，按就是关键字（key），f()就是哈希函数，查到的页码4就是哈希值。</p>
                    
                    <div class="bg-blue-50 p-4 rounded-lg mb-4">
                        <h4 class="font-semibold text-blue-800 mb-2">示例</h4>
                        <p class="text-sm">现有 1 ，3，4，5，6，9几个数进行储存，将n%10求模运算的结果作为哈希地址进行元素插入。</p>
                    </div>
                    
                    <p>若想查找某一元素时，则只需要对查找元素进行哈希函数运算，得到其存放地址，就能找到该元素。</p>
                </div>
                
                <div>
                    <img src="https://cdn.nlark.com/yuque/0/2021/png/21449790/1630846036617-fe9e3a52-481e-4945-9315-ed284a58d285.png" alt="哈希表示意图" class="w-full h-auto data-structure-img">
                </div>
            </div>
            
            <div class="grid md:grid-cols-2 gap-8">
                <div class="highlight p-6 bg-white rounded-xl">
                    <h3 class="text-2xl font-semibold mb-4 text-purple-600">Hash特点</h3>
                    <ul class="space-y-3">
                        <li class="flex items-start">
                            <div class="flex-shrink-0 h-6 w-6 text-purple-500 mr-2">1.</div>
                            <span>从hash值不可以反向推导出原始的数据</span>
                        </li>
                        <li class="flex items-start">
                            <div class="flex-shrink-0 h-6 w-6 text-purple-500 mr-2">2.</div>
                            <span>输入数据的微小变化会得到完全不同的hash值，相同的数据会得到相同的值</span>
                        </li>
                        <li class="flex items-start">
                            <div class="flex-shrink-0 h-6 w-6 text-purple-500 mr-2">3.</div>
                            <span>哈希算法的执行效率要高效，长的文本也能快速地计算出哈希值</span>
                        </li>
                        <li class="flex items-start">
                            <div class="flex-shrink-0 h-6 w-6 text-purple-500 mr-2">4.</div>
                            <span>hash算法的冲突概率要小</span>
                        </li>
                    </ul>
                    
                    <div class="mt-6 p-4 bg-yellow-50 rounded-lg">
                        <p class="text-sm">由于hash的原理是将输入空间的值映射成hash空间内，而hash值的空间远小于输入的空间。根据抽屉原理，一定会存在不同的输入被映射成相同输出的情况。</p>
                        <p class="text-sm mt-2 font-medium">抽屉原理:桌上有十个苹果，要把这十个苹果放到九个抽屉里，无论怎样放，我们会发现至少会有一个抽屉里面放不少于两个苹果。</p>
                    </div>
                </div>
                
                <div class="highlight p-6 bg-white rounded-xl">
                    <h3 class="text-2xl font-semibold mb-4 text-purple-600">Hash冲突/碰撞</h3>
                    <p class="mb-4">当出现插入一个元素，其根据哈希函数计算出的地址，已经被其他元素占用的情况称为哈希冲突。如：为了能更好的识别当前位置是否被占用，我们需要对每个位置进行标记。</p>
                    
                    <img src="https://cdn.nlark.com/yuque/0/2021/png/21449790/1630846052560-1b4d9079-fc8c-47c6-8c74-f66cd1f62527.png" alt="哈希冲突示例" class="w-full h-auto mb-4 data-structure-img">
                    
                    <p class="mb-4">如果遇到冲突，哈希表一般是怎么解决的呢？接下来解释的是最常用的一种方法<strong>拉链法</strong>，我们可以理解为"链表的数组"</p>
                    
                    <img src="https://cdn.nlark.com/yuque/0/2021/png/21449790/1630846066754-e4111eab-de6d-4450-8bd0-93f363efa49b.png" alt="哈希拉链法" class="w-full h-auto data-structure-img">
                    
                    <div class="mt-4">
                        <p>左边很明显是个数组，数组的每个成员包括一个指针，指向一个链表的头，当然这个链表可能为空，也可能元素很多。我们根据元素的一些特征把元素分配到不同的链表中去，也是根据这些特征，找到正确的链表，再从链表中找出这个元素。</p>
                    </div>
                </div>
            </div>
            
            <div class="mt-8">
                <h3 class="text-2xl font-semibold mb-4 text-purple-600">Hash冲突的原因</h3>
                <p class="mb-6">使用hash结构目的就是为了提高查询效率，数组的长度有限度的，但是储存的数据是无限制的，这种情况下必然会出现hash冲突。</p>
                
                <div class="grid md:grid-cols-2 gap-6">
                    <div class="highlight p-6 bg-white rounded-xl">
                        <h4 class="font-semibold mb-3">Object类HashCode方法</h4>
                        <div class="code-block p-4 rounded-lg">
                            <pre><code class="text-sm text-gray-200">public native int hashCode();</code></pre>
                        </div>
                    </div>
                    
                    <div class="highlight p-6 bg-white rounded-xl">
                        <h4 class="font-semibold mb-3">String类中hashCode方法</h4>
                        <div class="code-block p-4 rounded-lg">
                            <pre><code class="text-sm text-gray-200">public int hashCode() {
    int h = hash;
    if (h == 0 && value.length > 0) {
        char val[] = value;
        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i];
        }
        hash = h;
    }
    return h;
}</code></pre>
                        </div>
                    </div>
                    
                    <div class="highlight p-6 bg-white rounded-xl">
                        <h4 class="font-semibold mb-3">Integer类中hashCode方法</h4>
                        <div class="code-block p-4 rounded-lg">
                            <pre><code class="text-sm text-gray-200">public int hashCode() {
    return Integer.hashCode(value);
}
public static int hashCode(int value) {
    return value;
}</code></pre>
                        </div>
                    </div>
                    
                    <div class="highlight p-6 bg-white rounded-xl">
                        <h4 class="font-semibold mb-3">Boolean中hashCode方法</h4>
                        <div class="code-block p-4 rounded-lg">
                            <pre><code class="text-sm text-gray-200">@Override
public int hashCode() {
    return Boolean.hashCode(value);
}

public static int hashCode(boolean value) {
    return value ? 1231 : 1237;
}</code></pre>
                        </div>
                    </div>
                </div>
                
                <div class="mt-6 highlight p-6 bg-white rounded-xl">
                    <h4 class="font-semibold mb-3">中文的hashCode</h4>
                    <div class="code-block p-4 rounded-lg mb-4">
                        <pre><code class="text-sm text-gray-200">String str = "我是中国人";
char[] chars = str.toCharArray();
for(int i =0;i&lt;chars.length;i++){
    System.out.println(chars[i]+" --> "+(int)chars[i]);
}
System.out.println("我".hashCode());</code></pre>
                    </div>
                    <img src="https://cdn.nlark.com/yuque/0/2022/png/21449790/1653961071552-fd08bdac-9404-4e96-95aa-759a8e68be04.png" alt="中文hashCode示例" class="w-full h-auto data-structure-img">
                </div>
                
                <div class="mt-6 highlight p-6 bg-white rounded-xl">
                    <div class="code-block p-4 rounded-lg">
                        <pre><code class="text-sm text-gray-200">// 不同的内容会出现相同的hashCode
System.out.println("Aa".hashCode());
System.out.println("BB".hashCode());</code></pre>
                    </div>
                    <img src="https://cdn.nlark.com/yuque/0/2023/png/21449790/1689126655741-ca59dbb1-650c-4c58-aeb9-b118a7c5b5d3.png" alt="相同hashCode示例" class="w-full h-auto mt-4 data-structure-img">
                </div>
                
                <div class="mt-6 highlight p-6 bg-white rounded-xl">
                    <h4 class="font-semibold mb-3">Double的hashCode</h4>
                    <div class="code-block p-4 rounded-lg">
                        <pre><code class="text-sm text-gray-200">@Override
public int hashCode() {
    return Double.hashCode(value);
}
public static int hashCode(double value) {
    long bits = doubleToLongBits(value);
    return (int)(bits ^ (bits >>> 32));
}
public static long doubleToLongBits(double value) {
    long result = doubleToRawLongBits(value);
    // Check for NaN based on values of bit fields, maximum
    // exponent and nonzero significand.
    if ( ((result & DoubleConsts.EXP_BIT_MASK) ==
          DoubleConsts.EXP_BIT_MASK) &&
         (result & DoubleConsts.SIGNIF_BIT_MASK) != 0L)
        result = 0x7ff8000000000000L;
    return result;
}</code></pre>
                    </div>
                </div>
            </div>
            
            <div class="mt-8">
                <h3 class="text-2xl font-semibold mb-4 text-purple-600">Hash冲突的解决方案</h3>
                <div class="grid md:grid-cols-2 gap-6">
                    <div class="highlight p-6 bg-white rounded-xl">
                        <h4 class="text-lg font-semibold mb-3">1. 开放定址法：</h4>
                        <p>所谓的开放定址法就是一旦发生了冲突，就去寻找下一个空的散列地址，只要散列表足够大，空的散列地址总能找到，并将记录存入</p>
                    </div>
                    
                    <div class="highlight p-6 bg-white rounded-xl">
                        <h4 class="text-lg font-semibold mb-3">2. 再哈希法：</h4>
                        <p>再哈希法又叫双哈希法，有多个不同的Hash函数，当发生冲突时，使用第二个，第三个，….，等哈希函数，计算地址，直到无冲突。虽然不易发生聚集，但是增加了计算时间。</p>
                    </div>
                    
                    <div class="highlight p-6 bg-white rounded-xl">
                        <h4 class="text-lg font-semibold mb-3">3. 链地址法：</h4>
                        <p>链地址法的基本思想是：每个哈希表节点都有一个next指针，多个哈希表节点可以用next指针构成一个单向链表，被分配到同一个索引上的多个节点可以用这个单向</p>
                    </div>
                    
                    <div class="highlight p-6 bg-white rounded-xl">
                        <h4 class="text-lg font-semibold mb-3">4. 建立公共溢出区：</h4>
                        <p>这种方法的基本思想是：将哈希表分为基本表和溢出表两部分，凡是和基本表发生冲突的元素，一律填入溢出表</p>
                    </div>
                </div>
            </div>
        </section>

        <!-- Binary Search Tree Section -->
        <section class="mb-16">
            <div class="flex items-center mb-6">
                <div class="bg-green-100 w-10 h-10 rounded-full flex items-center justify-center mr-4">
                    <i class="fas fa-project-diagram text-green-600"></i>
                </div>
                <h2 class="text-3xl font-bold font-serif">二叉搜索树</h2>
            </div>
            
            <div class="mb-6">
                <a href="https://www.cs.usfca.edu/~galles/visualization/Algorithms.html" class="text-blue-600 hover:text-blue-800 font-medium flex items-center">
                    <i class="fas fa-external-link-alt mr-2"></i>
                    https://www.cs.usfca.edu/~galles/visualization/Algorithms.html
                </a>
            </div>
            
            <div class="grid md:grid-cols-2 gap-8">
                <div class="highlight p-6 bg-white rounded-xl">
                    <p class="mb-4">二叉查找/搜索/排序树  BST  (binary search/sort tree)</p>
                    <p>二叉树是n(n>=0)个结点的有限集合，该集合或者为空集（称为空二叉树），或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树组成。</p>
                </div>
                
                <div>
                    <img src="https://cdn.nlark.com/yuque/0/2021/png/21449790/1630846077247-6d0911df-9441-43b7-a2f4-59901819996b.png" alt="二叉搜索树示例" class="w-full h-auto data-structure-img">
                </div>
            </div>
            
            <div class="mt-8">
                <h3 class="text-2xl font-semibold mb-4 text-green-600">二叉搜索树的特点</h3>
                <p class="mb-4">由二叉树定义以及图示分析得出二叉树有以下特点：</p>
                
                <ul class="space-y-3 mb-6">
                    <li class="flex items-start">
                        <div class="flex-shrink-0 h-6 w-6 text-green-500 mr-2">1.</div>
                        <span>每个结点最多有两颗子树，<strong>所以二叉树中不存在大于2的字节点。</strong></span>
                    </li>
                    <li class="flex items-start">
                        <div class="flex-shrink-0 h-6 w-6 text-green-500 mr-2">2.</div>
                        <span>若它的左子树不空，则左子树上所有结点的值均小于它的根节点的值；</span>
                    </li>
                    <li class="flex items-start">
                        <div class="flex-shrink-0 h-6 w-6 text-green-500 mr-2">3.</div>
                        <span>若它的右子树上所有结点的值均大于它的根节点的值；</span>
                    </li>
                    <li class="flex items-start">
                        <div class="flex-shrink-0 h-6 w-6 text-green-500 mr-2">4.</div>
                        <span>它的左、右子树也分别为二叉排序树。</span>
                    </li>
                    <li class="flex items-start">
                        <div class="flex-shrink-0 h-6 w-6 text-green-500 mr-2">5.</div>
                        <span>对二叉树进行左中右遍历可以得到有序的结果集</span>
                    </li>
                </ul>
                
                <div class="bg-green-50 p-4 rounded-lg">
                    <p class="mb-2">二叉排序树就既有链表的好处，也有数组的好处。在处理大批量的动态的数据是比较有用。文件系统和数据库系统一般都采用树（特别是B树）的数据结构数据，主要为排序和检索的效率。</p>
                    <p class="font-medium"><strong>二叉树缺点也比较明显，在进行有序储存的时候就成变成一个链表，此时插入和查询效率也会降低。</strong></p>
                </div>
            </div>
        </section>

        <!-- AVL Tree Section -->
        <section class="mb-16">
            <div class="flex items-center mb-6">
                <div class="bg-teal-100 w-10 h-10 rounded-full flex items-center justify-center mr-4">
                    <i class="fas fa-balance-scale text-teal-600"></i>
                </div>
                <h2 class="text-3xl font-bold font-serif">平衡二叉树</h2>
            </div>
            
            <div class="grid md:grid-cols-2 gap-8">
                <div class="highlight p-6 bg-white rounded-xl">
                    <p>平衡二叉树（Self-balancing binary search tree）  自平衡二叉查找树  又被称为AVL树（有别于AVL算法）它是一 棵空树或它的左右两个子树的高度差(平衡因子)的绝对值不超过1，并且左右两个子树都是一棵平衡二叉树，同时，平衡二叉树必定是二叉搜索树，反之则不一定。<strong>平衡二叉树的目的是为了减少二叉查找树层次，提高查找速度</strong></p>
                </div>
                
                <div>
                    <img src="https://cdn.nlark.com/yuque/0/2021/png/21449790/1630846084782-f4070dc5-3522-4502-b31d-ccd4967c73eb.png" alt="平衡二叉树示例" class="w-full h-auto data-structure-img">
                </div>
            </div>
        </section>

        <!-- Red-Black Tree Section -->
        <section class="mb-16">
            <div class="flex items-center mb-6">
                <div class="bg-red-100 w-10 h-10 rounded-full flex items-center justify-center mr-4">
                    <i class="fas fa-tree text-red-600"></i>
                </div>
                <h2 class="text-3xl font-bold font-serif">红黑树</h2>
            </div>
            
            <div class="grid md:grid-cols-2 gap-8">
                <div class="highlight p-6 bg-white rounded-xl">
                    <p class="mb-4">红黑树也是一个平二叉树，因为平衡二叉树是<strong>绝对的平衡</strong>，每次插入删除时都要维持树的绝对的平衡，所以它自旋的次数就很多，自旋次数多了就影响了插入和删除的速度。此时红黑树就出来了，它强调的是相对平衡，树的两边差不多平衡就可以了,所以插入删除的时候就不会有太多的自旋。所以红黑树是一个相对平衡的一个树，而AVL树是一个决定平衡的树。所以红黑树放弃了决定平衡从而提升整体的一个性能。</p>
                    <p><strong>红黑树中左右两边子树的高度差不能超过2倍，超过2倍就要自旋。</strong></p>
                </div>
                
                <div>
                    <img src="https://cdn.nlark.com/yuque/0/2021/png/21449790/1638087404020-4ce0e480-439f-4256-92d3-a90694055c8b.png" alt="红黑树示例" class="w-full h-auto data-structure-img">
                </div>
            </div>
        </section>

        <!-- B-Tree Section -->
        <section class="mb-16">
            <div class="flex items-center mb-6">
                <div class="bg-orange-100 w-10 h-10 rounded-full flex items-center justify-center mr-4">
                    <i class="fas fa-sitemap text-orange-600"></i>
                </div>
                <h2 class="text-3xl font-bold font-serif">B树</h2>
            </div>
            
            <div class="grid md:grid-cols-2 gap-8 mb-8">
                <div class="highlight p-6 bg-white rounded-xl">
                    <p class="mb-4">红黑树中随着节点的增加，树会变的越来越深，树越深造成树的高度就越高，树的高度变高了IO次数就多了。反推如果想要减少IO次数就必须要降低树的高度，如何才能降低树的高度呢？或者说树高度是什么原因导致的呢？根本原因就是二叉树的特点，每个节点最多只有左右两个子节点。如果抛开二叉树，每个节点下面可以放多个子节点就解决了树的高度问题，此时AVL树就演变成了<strong>B树</strong>。</p>
                    
                    <div class="bg-orange-50 p-4 rounded-lg mt-4">
                        <p class="text-sm">我们可以根据B类树的特点，构造一个多阶的B类树，然后尽量多在节点上多存储相关的信息，保证层数尽量的少，以便后面我们可以更快的找到信息，磁盘的I/O操作也少一些，而且B类树是平衡树，每个结点到叶子结点的高度都是相同，这也保证了每个查询是稳定的</p>
                    </div>
                </div>
                
                <div>
                    <img src="https://cdn.nlark.com/yuque/0/2021/png/21449790/1638090623161-9990774c-c71b-4014-83b1-3f44ef8ec283.png" alt="B树示例" class="w-full h-auto data-structure-img">
                    <img src="https://cdn.nlark.com/yuque/0/2021/png/21449790/1638090668522-3ab9694e-9b91-4dad-85f2-c501354c876a.png" alt="B树结构" class="w-full h-auto mt-4 data-structure-img">
                </div>
            </div>
            
            <div class="highlight p-6 bg-white rounded-xl mb-8">
                <h3 class="text-2xl font-semibold mb-4 text-orange-600">B树中的度数(阶数)</h3>
                <p class="mb-4">每个节点（结点）所包含的关键字个数有上界和下界。用一个被称为B树的最小度数（minmum degree）的固定整数t>=2来表示这些界。</p>
                
                <ul class="space-y-3">
                    <li class="flex items-start">
                        <div class="flex-shrink-0 h-6 w-6 text-orange-500 mr-2">a.</div>
                        <span>除根节点外每个节点至少包含 t-1 个关键字；至少有t个孩子。</span>
                    </li>
                    <li class="flex items-start">
                        <div class="flex-shrink-0 h-6 w-6 text-orange-500 mr-2">b.</div>
                        <span>每个节点至多可包含 2t-1 个关键字，至多 2t 个孩子节点。</span>
                    </li>
                </ul>
            </div>
            
            <div class="grid md:grid-cols-2 gap-8 mb-8">
                <div class="highlight p-6 bg-white rounded-xl">
                    <h3 class="text-2xl font-semibold mb-4 text-orange-600">AVL数和B数对比</h3>
                    <img src="https://cdn.nlark.com/yuque/0/2021/png/21449790/1638093762586-06d2a7c7-3e80-4d4b-9a3c-1c6892be12ed.png" alt="AVL与B树对比" class="w-full h-auto data-structure-img">
                    
                    <p class="mt-4">可以看到，B 树的每个节点可以表示的信息更多，因此整个树更加"矮胖"，这在从磁盘中查找数据的过程中，可以减少磁盘 IO 的次数，从而提升查找速度。</p>
                </div>
                
                <div class="highlight p-6 bg-white rounded-xl">
                    <h3 class="text-2xl font-semibold mb-4 text-orange-600">B树每个节点由两部分组成：</h3>
                    <ul class="space-y-3">
                        <li class="flex items-start">
                            <div class="flex-shrink-0 h-6 w-6 text-orange-500 mr-2">1.</div>
                            <span><strong>关键字（可以理解为数据）</strong></span>
                        </li>
                        <li class="flex items-start">
                            <div class="flex-shrink-0 h-6 w-6 text-orange-500 mr-2">2.</div>
                            <span><strong>指向孩子节点的指针</strong></span>
                        </li>
                    </ul>
                    
                    <div class="mt-6">
                        <h4 class="text-lg font-semibold mb-3">数据页</h4>
                        <p class="mb-2"><strong>数据页页是mysql中磁盘和内存交换的基本单位，也是mysql管理存储空间的基本单位</strong>。同一个数据库实例的所有表空间都有相同的页大小；默认情况下，表空间中的页大小都为 16KB，当然也可以通过改变 innodb_page_size 选项对默认大小进行修改，需要注意的是不同的页大小最终也会导致区大小的不同。<strong>. 一次最少从磁盘读取16KB内容到内存中</strong>，一次最少把内存中16KB内容刷新到磁盘中，当然了单页读取代价也是蛮高的，一般都会进行预读。</p>
                    </div>
                </div>
            </div>
            
            <div class="grid md:grid-cols-2 gap-8">
                <div>
                    <img src="https://cdn.nlark.com/yuque/0/2021/png/21449790/1638096633964-9d3ef4e0-50c0-4d2a-9be7-874ef8a297ae.png" alt="数据页示意图" class="w-full h-auto data-structure-img">
                </div>
                
                <div class="highlight p-6 bg-white rounded-xl">
                    <h3 class="text-2xl font-semibold mb-4 text-orange-600">B数做储存索引</h3>
                    <img src="https://cdn.nlark.com/yuque/0/2021/png/21449790/1638097355872-4f3e0dda-f122-4ed2-8f1b-c2968e82658f.png" alt="B树索引示例" class="w-full h-auto mb-4 data-structure-img">
                    
                    <p>这里每一个磁盘块都是一个数据页，因为B树的每个节点中都包含了<strong>主键，数据和指针</strong>，它们都是要占用空间的，所以每个节点中包含的数据就变少了，如果此时需要查询id为7的数据，需要加载三块磁盘也就是要3次IO。所以B树又演变成了B+树来解决这个问题，它的IO次数会更少。</p>
                </div>
            </div>
        </section>

        <!-- B+ Tree Section -->
        <section>
            <div class="flex items-center mb-6">
                <div class="bg-indigo-100 w-10 h-10 rounded-full flex items-center justify-center mr-4">
                    <i class="fas fa-network-wired text-indigo-600"></i>
                </div>
                <h2 class="text-3xl font-bold font-serif">B+树</h2>
            </div>
            
            <div class="grid md:grid-cols-2 gap-8 mb-8">
                <div class="highlight p-6 bg-white rounded-xl">
                    <p>B+树是应文件系统所需而产生的一种B树的变形树（文件的目录一级一级索引，只有<strong>最底层的叶子节点（文件）保存数据</strong>）非叶子节点只保存索引，不保存实际的数据，数据都保存在叶子节点中。</p>
                </div>
                
                <div>
                    <img src="https://cdn.nlark.com/yuque/0/2021/png/21449790/1638097961672-f776aeef-6fee-440b-9a36-cc522e74cf78.png" alt="B+树示例" class="w-full h-auto data-structure-img">
                </div>
            </div>
            
            <div class="highlight p-6 bg-white rounded-xl mb-8">
                <h3 class="text-2xl font-semibold mb-4 text-indigo-600">B+树的特点：</h3>
                <ul class="space-y-3">
                    <li class="flex items-start">
                        <div class="flex-shrink-0 h-6 w-6 text-indigo-500 mr-2">1.</div>
                        <span><strong>B+Tree 的根节点和枝节点中都不会存储数据(索引)，只有叶子节点才存储数据。</strong></span>
                    </li>
                    <li class="flex items-start">
                        <div class="flex-shrink-0 h-6 w-6 text-indigo-500 mr-2">2.</div>
                        <span>B+Tree 的每个叶子节点增加了一个指向相邻叶子节点的指针，它的最后一个数据会指向下一个叶子节点的第一个数据，形成了一个有序链表的结构。</span>
                    </li>
                </ul>
                
                <div class="mt-6">
                    <img src="https://cdn.nlark.com/yuque/0/2021/png/21449790/1638099695570-c3259033-3647-4f45-b27d-2fedfff47039.png" alt="B+树有序链表" class="w-full h-auto data-structure-img">
                </div>
            </div>
            
            <div class="highlight p-6 bg-white rounded-xl">
                <h3 class="text-2xl font-semibold mb-4 text-indigo-600">为什么说B+树比B树更适合数据库索引？</h3>
                
                <ul class="space-y-4">
                    <li class="flex items-start">
                        <div class="flex-shrink-0 h-6 w-6 text-indigo-500 mr-2">1.</div>
                        <div>
                            <p><strong>B+树的磁盘读写代价更低：B+树的内部节点并没有指向关键字具体信息的指针，因此其内部节点相对B树更小，如果把所有同一内部节点的关键字存放在同一盘块中，那么盘块所能容纳的关键字数量也越多，一次性读入内存的需要查找的关键字也就越多，相对IO读写次数就降低了。</strong></p>
                        </div>
                    </li>
                    <li class="flex items-start">
                        <div class="flex-shrink-0 h-6 w-6 text-indigo-500 mr-2">2.</div>
                        <div>
                            <p><strong>B+树的查询效率更加稳定：由于非终结点并不是最终指向文件内容的结点，而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同，导致每一个数据的查询效率相当。</strong></p>
                        </div>
                    </li>
                    <li class="flex items-start">
                        <div class="flex-shrink-0 h-6 w-6 text-indigo-500 mr-2">3.</div>
                        <div>
                            <p>由于B+树的数据都存储在叶子结点中，分支结点均为索引，方便扫库，只需要扫一遍叶子结点即可，但是B树因为其分支结点同样存储着数据，我们要找到具体的数据，需要进行一次中序遍历按序来扫，所以B+树更加适合在区间查询的情况，所以通常B+树用于数据库索引。</p>
                        </div>
                    </li>
                </ul>
            </div>
        </section>
    </div>

    <script>
        mermaid.initialize({
            startOnLoad: true,
            theme: 'default',
            flowchart: {
                useMaxWidth: true,
                htmlLabels: true,
                curve: 'basis'
            }
        });
    </script>
</body>
</html>
```